package com.xyazm.order.statemachine.action.order.create.node;

import com.xyazm.common.logger.LoggerFormat;
import com.xyazm.order.dao.*;
import com.xyazm.order.domain.builder.FullOrderData;
import com.xyazm.order.domain.dto.OrderInfoDTO;
import com.xyazm.order.domain.entity.*;
import com.xyazm.order.domain.holder.NewOrderDataHolder;
import com.xyazm.order.mapstruct.OrderApiMapstruct;
import com.xyazm.process.engine.process.ProcessContext;
import com.xyazm.process.engine.process.StandardProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 保存订单信息到数据库节点
 * @author xuyou
 * @date 2023年02月02日 21:13
 */
@Slf4j
@Component
public class CreateOrderDBNode extends StandardProcessor {

    @Resource
    private TransactionTemplate transactionTemplate;

    @Autowired
    private OrderInfoDAO orderInfoDAO;

    @Autowired
    private OrderItemDAO orderItemDAO;

    @Autowired
    private OrderDeliveryDetailDAO orderDeliveryDetailDAO;

    @Autowired
    private OrderPaymentDetailDAO orderPaymentDetailDAO;

    @Autowired
    private OrderAmountDAO orderAmountDAO;

    @Autowired
    private OrderAmountDetailDAO orderAmountDetailDAO;

    @Autowired
    private OrderOperateLogDAO orderOperateLogDAO;

    @Autowired
    private OrderSnapshotDAO orderSnapshotDAO;

    @Autowired
    private OrderCancelScheduledTaskDAO orderCancelScheduledTaskDAO;


    @Override
    protected void processInternal(ProcessContext context) {
        //  @Transactional无法生效，需要用编程式事务
        transactionTemplate.execute(transactionStatus -> {
            FullOrderData fullOrderData = context.get("fullMasterOrderData");
            NewOrderDataHolder newOrderDataHolder = context.get("newOrderDataHolder");
            String orderId = fullOrderData.getOrderInfoDO().getOrderId();

            // 订单信息
            List<OrderInfoDO> orderInfoDOList = newOrderDataHolder.getOrderInfoDOList();
            if (!orderInfoDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单信息").data("orderId", orderId).finish());
                orderInfoDAO.saveBatch(orderInfoDOList);
            }

            // 订单条目
            List<OrderItemDO> orderItemDOList = newOrderDataHolder.getOrderItemDOList();
            if (!orderItemDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单条目").data("orderId", orderId).finish());
                orderItemDAO.saveBatch(orderItemDOList);
            }

            // 订单配送信息
            List<OrderDeliveryDetailDO> orderDeliveryDetailDOList = newOrderDataHolder.getOrderDeliveryDetailDOList();
            if (!orderDeliveryDetailDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单配送信息").data("orderId", orderId).finish());
                orderDeliveryDetailDAO.saveBatch(orderDeliveryDetailDOList);
            }

            // 订单支付信息
            List<OrderPaymentDetailDO> orderPaymentDetailDOList = newOrderDataHolder.getOrderPaymentDetailDOList();
            if (!orderPaymentDetailDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单支付信息").data("orderId", orderId).finish());
                orderPaymentDetailDAO.saveBatch(orderPaymentDetailDOList);
            }

            // 订单费用信息
            List<OrderAmountDO> orderAmountDOList = newOrderDataHolder.getOrderAmountDOList();
            if (!orderAmountDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单费用信息").data("orderId", orderId).finish());
                orderAmountDAO.saveBatch(orderAmountDOList);
            }

            // 订单费用明细
            List<OrderAmountDetailDO> orderAmountDetailDOList = newOrderDataHolder.getOrderAmountDetailDOList();
            if (!orderAmountDetailDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存订单费用明细").data("orderId", orderId).finish());
                orderAmountDetailDAO.saveBatch(orderAmountDetailDOList);
            }

            // 插入用于验证订单是否超时的兜底任务记录 只取主单信息 保存主单order记录
            List<OrderInfoDO> masterOrderInfoDOList = orderInfoDOList.stream()
                    .filter(orderInfoDO -> orderInfoDO.getParentOrderId() == null).collect(Collectors.toList());
            if (!masterOrderInfoDOList.isEmpty()) {
                log.info(LoggerFormat.build().remark("保存定时执行订单取消兜底任务记录").data("orderId", orderId).finish());
                OrderInfoDO orderInfoDO = masterOrderInfoDOList.get(0);
                orderCancelScheduledTaskDAO.saveOne(orderInfoDO.getOrderId(), orderInfoDO.getExpireTime());
            }

            OrderInfoDTO orderInfoDTO = OrderApiMapstruct.INSTANCE.convertOrderInfoDTO(fullOrderData.getOrderInfoDO());
            context.set("orderInfoDTO", orderInfoDTO);

            // 事务提交成功后执行
            TransactionSynchronizationManager.registerSynchronization(
                    new TransactionSynchronizationAdapter() {
                      @Override
                      public void afterCommit() {
                          // 订单状态变更日志信息
                          List<OrderOperateLogDO> orderOperateLogDOList = newOrderDataHolder.getOrderOperateLogDOList();
                          if (!orderOperateLogDOList.isEmpty()) {
                              log.info(LoggerFormat.build().remark("保存订单状态变更日志信息").data("orderId", orderId).finish());
                              // 后期把数据放到MongoDB
                              orderOperateLogDAO.saveBatch(orderOperateLogDOList);
                          }
                          // 订单快照数据
                          List<OrderSnapshotDO> orderSnapshotDOList = newOrderDataHolder.getOrderSnapshotDOList();
                          if (!orderSnapshotDOList.isEmpty()) {
                              log.info(LoggerFormat.build().remark("保存订单快照数据").data("orderId", orderId).finish());
                              // 后期把数据放到HBase
                              orderSnapshotDAO.saveBatch(orderSnapshotDOList);
                          }
                      }
                  }
            );
            return true;
        });
    }
}
